package me.seawenc.db.migration.dbengine.impl.engines;

import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import me.seawenc.db.migration.bean.TableBean;
import me.seawenc.db.migration.bean.table.TableIndexBean;
import me.seawenc.db.migration.bean.table.TablePartitionBean;
import me.seawenc.db.migration.bean.table.TableRefBean;
import me.seawenc.db.migration.dbengine.DbType;
import me.seawenc.db.migration.dbengine.IEngineService;
import me.seawenc.db.migration.bean.FileConfig;
import me.seawenc.db.migration.dbengine.impl.engines.bean.TableNameBean;
import me.seawenc.db.migration.dbengine.impl.utils.SqlActuator;
import me.seawenc.db.migration.helper.FileHelper;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import me.seawenc.db.migration.service.translator.BaseTranslator;

import static me.seawenc.db.migration.dbengine.impl.engines.constant.ConstantFieldName.*;

/**
 * 所有具体实现都必须继承此类，做为模版方法
 */
public abstract class EngineServiceBase implements IEngineService {
    /**
     * sql文件中，对表名的变更代码
     */
    protected  static final String VAR_PARAM_TABLE_NAME = "_table_name_";

    /**
     * sql文件的基础路径
     */
    protected final String sqlsBasePath="/sqls/"+getDsType().lname();

    protected final String dbVersion;

    /**
     * sql执行器
     */
    protected SqlActuator sqlActuator;

    /**
     * 将逻辑模型翻译成 物理模型， 将物理模型翻译成逻辑模型
     */
    BaseTranslator translator;
    /**
     * 数据源类型
     * @return
     */
    protected abstract DbType getDsType();

    public EngineServiceBase(FileConfig conf) throws Exception {
        sqlActuator =new SqlActuator(conf);
        dbVersion=findVersion();

    }

    @Override
    public BaseTranslator getTranslator() {
        return null;
    }

    @Override
    public String findVersion() throws Exception {
        String sql = getVersionSql(getDsType().lname());
        return execSqlTemplete(sql).get(0).getString(VERSION.toString());
    }


    @Override
    public List<TableNameBean> findAllTables() throws Exception {
        String sql = getAllTablesSql();
        List<JSONObject> jsonObjects = execSqlTemplete(sql);
        return jsonObjects
                .stream()
                .map(v -> new TableNameBean(v.getString(TAB_NAME.toString()), v.getString(COMMENT.toString())))
                .collect(Collectors.toList());
    }

    public TableBean findTableInfo(String tableName) throws Exception{
        return execFindTableColumns(tableName);
    }

    @Override
    public TableBean findTableDetail(String tableName) throws Exception {
        TableBean detail = findTableInfo(tableName);
        detail.setRefs(findTableRefs(tableName));
        detail.setIndexs(findTableIndexs(tableName));
        detail.setPartitions(findTablePartitions(tableName));
        return detail;
    }

    @Override
    public List<TableRefBean> findTableRefs(String tableName) throws Exception {
        String sql = findSql("/select_table_ref.sql",tableName);
        List<JSONObject> jsonObjects = execSqlTemplete(sql);
        return TableRefBean.createInstance(jsonObjects);
    }

    public List<TableIndexBean> findTableIndexs(String tableName) throws Exception{
        String sql = findSql("/select_table_indexs.sql",tableName);
        List<JSONObject> jsonObjects = execSqlTemplete(sql);
        return jsonObjects.stream().map(json-> new TableIndexBean(json)).collect(Collectors.toList());
    }

    public List<TablePartitionBean> findTablePartitions(String tableName) throws Exception{
        // fixme 等待实现
        return new ArrayList<>();
    }

    @Override
    public List<JSONObject> execSelectSql(String sql) throws Exception {
        return execSqlTemplete(sql);
    }

    /**
     * 获得所查询所有表的sql
     * @return
     */
    protected String getAllTablesSql(){
        return findSql("/select_all_tables.sql");
    }

    /**
     * 获得查询数据库版本sql
     * @return
     */
    protected String getVersionSql(String extType){
        return findSql("/select_version.sql",extType);
    }

    /**
     * 查找sql
     * @param sqlFileName sql文件名
     * @return
     */
    protected String findSql(String sqlFileName){
        String fullFilePath=String.format("%s/%s%s",sqlsBasePath,dbVersion,sqlFileName);
        // 如果有对应版本sql，则优先使用
        if (FileHelper.resFileExist(fullFilePath)){
            return FileHelper.readResFile(fullFilePath);
        }
        return FileHelper.readResFile(sqlsBasePath+sqlFileName);
    }

    protected String findSql(String sqlFileName,String tableName){
        return findSql(sqlFileName).replace(VAR_PARAM_TABLE_NAME, Optional.ofNullable(tableName).orElse(""));
    }

    /**
     * 表结构sql
     *
     * @param tableName
     * @return
     */
    protected String getTableDescribeSql(String tableName){
        return findSql("/select_table_describe.sql",tableName);
    }

    /**
     * 查询表字段
     * @param tableName
     * @return
     * @throws Exception
     */
    protected TableBean execFindTableColumns(String tableName) throws Exception {
        List<JSONObject> ret = sqlActuator.execQuerySql(getTableDescribeSql(tableName));
        return new TableBean(tableName,ret);
    }

    @Override
    public boolean hasData(String tableName) throws Exception {
        String sql = findSql("/has_datas.sql", tableName);
        List<JSONObject> jsonObjects = sqlActuator.execQuerySql(sql);
        return jsonObjects.size()>0;
    }

    /**
     * sql执行模版，sql执行完后就关闭数据库连接
     * @param sql
     * @return
     * @throws Exception
     */
    protected List<JSONObject> execSqlTemplete(String sql) throws Exception {
        List<JSONObject> ret = sqlActuator.execQuerySql(sql);
        return ret;
    }

    @Override
    public void closeDbCollection() throws Exception {
        sqlActuator.close();
    }
}
